<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/index.css">
    <link rel="stylesheet" href="css/main.css">
    <style>
        .custom-tree-node {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: space-between;
            font-size: 14px;
            padding-right: 8px;
        }
    </style>
</head>
<body>
    <div id="app">
        <el-container>
            <el-aside width="250px">
                <el-row>
                    <el-col :span="24">
                        <el-row>
                            <el-col :span="10">
                                <strong>连接列表</strong>
                            </el-col>
                            <el-col :span="14">
                                <el-button @click="addConnection()" size="mini" round>添加</el-button>
                                <el-button @click="refreshConnection" size="mini" round>刷新</el-button>
                            </el-col>
                        </el-row>
                        <rl-row>
                            <div class="custom-tree-container">
                                <div class="block">
                                    <el-tree
                                        v-if="showConnection"
                                        accordion
                                        lazy
                                        :load="loadNode"
                                        :data="treeData"
                                        :props="treeProps"
                                        :expand-on-click-node="false"
                                        @node-expand="handleNodeClick"
                                        @node-collapse="handleNodeClick"
                                        @node-click="handleNodeClick"
                                    >
                                    <span style="text-align: right" class="custom-tree-node" slot-scope="{ node, data }">
                                        <span>{{ node.label }}</span>
                                        <span>
                                          <el-button
                                              v-if="data.deep === 1"
                                              type="text"
                                              size="mini"
                                              @click="addConnection(data.id)">
                                              编辑
                                          </el-button>
                                          <el-button
                                              v-if="data.deep === 1"
                                              type="text"
                                              size="mini"
                                              @click="deleteConnection(data.id)">
                                              删除
                                          </el-button>
                                        </span>
                                      </span>
                                    </el-tree>
                                </div>
                            </div>
                        </rl-row>
                    </el-col>
                </el-row>
            </el-aside>
            <el-main class="el-main-top0">
                <el-row>
                    <span class="span-bold">当前连接：</span>
                    <span>{{ oneNode.find(o => o.id === connectionId)?.name }}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <span class="span-bold">当前数据库：</span>
                    <span>{{ database }}</span>
                </el-row>
                <el-row>
                    <el-input class="query-button"
                            type="textarea"
                            :rows="10"
                            v-model="sql"
                            @keyup.ctrl.enter.native="handleKeyCtrlEnter"
                    >
                    </el-input>
                </el-row>
                <el-row type="flex" justify="end" class="query-button">
                    <el-button @click="query">查询</el-button>
                    <el-button @click="clear">清空</el-button>
                </el-row>
                <el-row class="query-button">
                    <pre class="log-pre">{{ logMsg }}</pre>
                </el-row>
                <el-row v-if="resultStatus == '1'">
                    <el-table
                            :data="tableRenderData"
                            height="500"
                            border
                            style="width: 100%">
                        <el-table-column
                                v-if="tableData.columns.length > 0"
                                type="index"
                                :index="indexMethod"
                                width="100">
                        </el-table-column>
                        <el-table-column
                                min-width="200"
                                v-for="(item, index) in tableData.columns"
                                :prop="item"
                                :label="item">
                        </el-table-column>
                    </el-table>
                    <el-pagination
                            @size-change="handleSizeChange"
                            @current-change="handleCurrentChange"
                            :current-page="pageData.currentPage"
                            :page-sizes="pageData.pageSizes"
                            :page-size="pageData.pageSize"
                            layout="total, sizes, prev, pager, next, jumper"
                            :total="pageData.total">
                    </el-pagination>
                </el-row>
            </el-main>
        </el-container>

        <el-dialog
            title="连接"
            :visible.sync="dialogVisible"
            width="30%">

            <el-form ref="connection" :model="connection" label-width="80px">
                <el-form-item label="连接名">
                    <el-input v-model="connection.name"></el-input>
                </el-form-item>
                <el-form-item label="IP地址">
                    <el-input v-model="connection.ip"></el-input>
                </el-form-item>
                <el-form-item label="端口">
                    <el-input v-model="connection.port"></el-input>
                </el-form-item>
                <el-form-item label="数据库">
                    <el-input v-model="connection.database"></el-input>
                </el-form-item>
                <el-form-item label="用户名">
                    <el-input v-model="connection.username"></el-input>
                </el-form-item>
                <el-form-item label="密码">
                    <el-input type="password" v-model="connection.password"></el-input>
                </el-form-item>
                <el-form-item label="SSL">
                    <el-radio-group v-model="connection.useSsl">
                        <el-radio :label="1">是</el-radio>
                        <el-radio :label="0">否</el-radio>
                    </el-radio-group>
                </el-form-item>
            </el-form>
            <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="testConnection">测 试</el-button>
                <el-button type="primary" @click="saveConnection">保 存</el-button>
            </span>
        </el-dialog>
    </div>
</body>
<script type="text/javascript" src="js/public.js"></script>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript" src="js/axios.min.js"></script>
<script type="text/javascript" src="js/qs.min.js"></script>
<script>
    new Vue({
        el: '#app',
        data: function() {
            return {
                // 前缀
                prefix: config.prefix,
                // 结果状态
                resultStatus: '',
                // 结果信息
                logMsg: ' ',
                // 当前连接列表
                oneNode: [],
                // 当前数据库列表
                twoNode: [],
                // 当前表列表
                threeNode: [],
                // 选中连接
                connectionId: '',
                // 选中数据库
                database: '',
                // 选中表
                table: '',
                // 执行SQL
                sql: '',
                // 添加连接弹框控制
                dialogVisible: false,
                // 树配置
                treeProps: {
                    label: 'name',
                    children: 'zones',
                    isLeaf: 'leaf'
                },
                // 是否显示连接树，用于刷新树
                showConnection: true,
                // 树节点双击认证
                nodeDoubleClick: {
                    id: '',
                    count: 0
                },
                // 双击定时器
                nodeDoubleTimeout: null,
                // 表格数据
                tableData: {
                    columns: [],
                    data: []
                },
                // 分页数据
                pageData: {
                    pageSizes: [100, 200, 500, 1000],
                    currentPage: 1,
                    pageSize: 100,
                    total: 0
                },
                // 连接列表
                connections: [],
                // 连接对象
                connection: {
                    id: '',
                    name: '',
                    ip: '',
                    port: '',
                    database: '',
                    username: '',
                    password: '',
                    useSsl: 0
                }
            }
        },
        methods: {
            /**
             * 执行
             * @param connectionId
             * @param database
             * @param sql
             * @param callback
             */
            execute(connectionId, database, sql, callback) {
                axios({
                    method: 'GET',
                    url: `${this.prefix}/client/query?` + Qs.stringify({
                        connectionId: connectionId,
                        database: database,
                        sql: sql
                    })
                })
                .then(response => {
                    callback(response.data);
                })
            },

            /**
             * 数据处理
             */
            dataProcessing(data) {
                this.logMsg = data?.msg;
                if (data && data.status) {
                    this.resultStatus = '1';
                    this.tableData.columns = data.data.columns;
                    this.tableData.data = data.data.data;
                    this.pageData.currentPage = 1;
                    this.pageData.total = data.data.data.length;
                } else {
                    this.resultStatus = '2';
                }
            },

            /**
             * 查询
             */
            query() {
                this.execute(this.connectionId, this.database, this.sql, (response) => {
                    this.dataProcessing(response);
                });
            },

            /**
             * 输入框组合键快速查询
             */
            handleKeyCtrlEnter() {
                this.query();
            },

            /**
             * 选中树
             * @param data
             */
            handleNodeClick(data) {
                console.log(data);
                if (data && data.deep === 1) {
                    if (this.connectionId !== data.id) {
                        this.database = '';
                    }
                    this.connectionId = data.id;
                } else if (data && data.deep === 2) {
                    this.database = data.name;
                } else if (data && data.deep === 3) {
                    this.table = data.name;
                }

                if (this.nodeDoubleClick.id === data.id) {
                    this.nodeDoubleClick.count++;
                    if (this.nodeDoubleClick.count > 1) {
                        if (data.deep === 3) {
                            if (this.sql != '') {
                                this.sql += `\nselect * from ${this.table} where time > now() - 5m`;
                            } else {
                                this.sql = `select * from ${this.table} where time > now() - 5m`;
                            }
                        }
                        this.nodeDoubleClick.count = 0;
                        clearTimeout(this.nodeDoubleTimeout);
                    }
                } else {
                    if (this.nodeDoubleTimeout) {
                        clearTimeout(this.nodeDoubleTimeout);
                    }
                    this.nodeDoubleClick.id = data.id;
                    this.nodeDoubleClick.count = 1;
                }
                this.nodeDoubleTimeout = setTimeout(() => {
                    this.nodeDoubleClick.count = 0;
                }, 500);
            },

            /**
             * 懒加载树
             * @param node
             * @param resolve
             * @returns {Promise<*>}
             */
            async loadNode(node, resolve) {
                if (node.level === 0) {
                    this.oneNode = [];
                    await this.request({
                        method: 'GET',
                        url: `${this.prefix}/client/connection`
                    },
                    data => {
                        this.connections = data.data;
                        this.connections.forEach(i => {
                            this.oneNode.push({
                                name: i.name,
                                id: i.id,
                                deep: 1
                            })
                        })
                    });
                    return resolve(this.oneNode);
                } else if (node.level === 1) {
                    this.connectionId = node.data.id;
                    this.twoNode = [];
                    await this.request({
                        method: 'GET',
                        url: `${this.prefix}/client/connection/databases?connectionId=${this.connectionId}`
                    },
                    data => {
                        data.data.forEach(i => {
                            this.twoNode.push({
                                name: i.name,
                                id: node.data.id + i.name,
                                deep: 2
                            })
                        })
                    });
                    return resolve(this.twoNode);
                } else if (node.level === 2) {
                    this.database = node.data.name;
                    this.threeNode = [];
                    await this.request({
                        method: 'GET',
                        url: `${this.prefix}/client/connection/measurements?connectionId=${this.connectionId}&database=${this.database}`
                    },
                    data => {
                        data.data.forEach(i => {
                            this.threeNode.push({
                                name: i.name,
                                id: node.data.id + i.name,
                                leaf: true,
                                deep: 3
                            })
                        })
                    });
                    return resolve(this.threeNode);
                } else {
                    return resolve([]);
                }
            },

            /**
             * 添加编辑连接
             */
            addConnection(id) {
                this.dialogVisible = true;
                this.clearConnection();
                if (id !== undefined) {
                    this.connection = this.connections.find(o => o.id === id);
                }
            },

            /**
             * 删除连接
             */
            deleteConnection(id) {
                this.$confirm('是否确认删除？', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.request({
                        method: 'DELETE',
                        url: `${this.prefix}/client/connection?id=${id}`,
                    },
                    data => {
                        this.$message({
                            showClose: true,
                            type: 'success',
                            message: '删除成功!'
                        });
                        this.refreshConnection();
                    });
                }).catch(() => {
                });
            },

            /**
             * 清空连接信息编辑数据
             */
            clearConnection() {
                this.connection = {
                    id: '',
                    name: '',
                    ip: '',
                    port: '',
                    database: '',
                    username: '',
                    password: '',
                    useSsl: 0
                };
            },

            /**
             * 刷新树
             */
            refreshConnection() {
                this.showConnection = false;
                this.connectionId = '';
                this.database = '';
                this.table = '';
                this.$nextTick(() => {
                    this.showConnection = true;
                });
            },

            /**
             * 切换页码
             * @param val
             */
            handleSizeChange(val) {
                this.pageData.currentPage = 1;
                this.pageData.pageSize = val;
            },

            /**
             * 怯寒当前页
             * @param val
             */
            handleCurrentChange(val) {
                this.pageData.currentPage = val;
            },

            /**
             * 自定义序列
             */
            indexMethod(index) {
                return (this.pageData.currentPage - 1) * this.pageData.pageSize + index + 1;
            },

            /**
             * 清空
             */
            clear() {
                this.logMsg = ' ';
                this.resultStatus = '';
                this.pageData.currentPage = 1;
                this.pageData.pageSize = 100;
                this.pageData.total = 0;
                this.tableData.columns = [];
                this.tableData.data = [];
            },

            /**
             * 保存连接
             */
            saveConnection() {
                this.request({
                    method: 'POST',
                    url: `${this.prefix}/client/connection`,
                    data: this.connection
                },
                data => {
                    this.dialogVisible = false;
                    this.refreshConnection();
                });
            },

            /**
             * 保存连接
             */
            testConnection() {
                this.request({
                    method: 'PUT',
                    url: `${this.prefix}/client/connection`,
                    data: this.connection
                },
                data => {
                    this.$message({
                        showClose: true,
                        type: 'success',
                        message: `连接成功，服务版本号：${data.msg}`
                    });
                });
            },

            /**
             * 请求函数
             * @param prop
             * @param successCallback
             * @param failCallback
             */
            async request(prop, successCallback, failCallback) {
                await axios(prop)
                    .then(response => {
                        if (response && response.data && response.data.status) {
                            successCallback(response.data);
                        } else {
                            if (failCallback !== undefined) {
                                failCallback(response.data);
                            } else {
                                if (response && response.data && response.data.msg) {
                                    this.$message({
                                        showClose: true,
                                        type: 'error',
                                        message: response.data.msg
                                    });
                                } else {
                                    this.$message({
                                        showClose: true,
                                        type: 'error',
                                        message: '操作失败!'
                                    });
                                }
                            }
                        }
                    })
                    .catch(err => {
                        console.log(err);
                        this.$message({
                            showClose: true,
                            type: 'error',
                            message: '操作失败!'
                        });
                    })
            }
        },
        computed: {
            tableRenderData() {
                const start = (this.pageData.currentPage - 1) * this.pageData.pageSize;
                const end = start + this.pageData.pageSize;
                return this.tableData.data.slice(start, end);
            }
        }
    })
</script>
</html>